﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using Noris.Tools.FrxEditor.Pics;
using System.Windows.Forms;
using Noris.Tools.FrxEditor.ReportObjects;
using Noris.Tools.FrxEditor.Data;

namespace Noris.Tools.FrxEditor.Editor
{
    #region class EditorCommandSet : Popisná data, deklarující jeden toolbar (sadu buttonů). Určuje umístění a obsah. Je vhodné k persistenci konfigurace a stavu, používá se pro tvorbu reálných toolbarů.
    /// <summary>
    /// EditorCommandSet : Popisná data, deklarující jeden toolbar (sadu buttonů).
    /// Obsahuje pouze popisná data (metadata).
    /// Určuje umístění a obsah.
    /// Je vhodné k persistenci konfigurace a stavu, používá se pro tvorbu reálných toolbarů.
    /// </summary>
    internal class EditorCommandSet
    {
        #region Konstruktor a property
        internal EditorCommandSet()
        {
            this.Commands = new List<EditorCommandKey>();
        }
        /// <summary>
        /// Klíč položky
        /// </summary>
        internal string Key { get; set; }
        /// <summary>
        /// Krátký textový popisek
        /// </summary>
        internal string Text { get; set; }
        /// <summary>
        /// Strana (panel), kde je toolbar zobrazen
        /// </summary>
        internal EditorToolLocation ToolSide { get; set; }
        /// <summary>
        /// Pozice odpovídajícího ToolStripu v rámci jeho hostitele
        /// </summary>
        internal Point ToolLocation { get; set; }
        /// <summary>
        /// Seznam klíčů commandů v toolbaru
        /// </summary>
        internal List<EditorCommandKey> Commands { get; set; }
        /// <summary>
        /// Přidá daný command
        /// </summary>
        /// <param name="commandKey"></param>
        internal void AddCommand(EditorCommandKey commandKey)
        {
            this.Commands.Add(commandKey);
        }
        /// <summary>
        /// Přidá sadu commandů
        /// </summary>
        /// <param name="commandKeys"></param>
        internal void AddCommands(params EditorCommandKey[] commandKeys)
        {
            foreach (EditorCommandKey commandKey in commandKeys)
                this.Commands.Add(commandKey);
        }
        #endregion
        #region Statické konstruktory konkrétních definic
        /// <summary>
        /// Statický konstruktor pro toolbar: Edit
        /// </summary>
        /// <returns></returns>
        internal static EditorCommandSet CreateEdit()
        {
            EditorCommandSet tool = new EditorCommandSet() { Key = "Edit", Text = "Editace", ToolSide = EditorToolLocation.Top };
            tool.AddCommands(new EditorCommandKey(EditorCommandType.Edit, EditorCommandEditType.EditCut),
                             new EditorCommandKey(EditorCommandType.Edit, EditorCommandEditType.EditCopy),
                             new EditorCommandKey(EditorCommandType.Edit, EditorCommandEditType.EditPaste),
                             new EditorCommandKey(EditorCommandType.Edit, EditorCommandEditType.EditDelete),
                             EditorCommandKey.Separator,
                             new EditorCommandKey(EditorCommandType.Edit, EditorCommandEditType.EditUndo),
                             new EditorCommandKey(EditorCommandType.Edit, EditorCommandEditType.EditRedo));
            return tool;
        }
        /// <summary>
        /// Statický konstruktor pro toolbar: Zoom
        /// </summary>
        /// <returns></returns>
        internal static EditorCommandSet CreateZoom()
        {
            EditorCommandSet tool = new EditorCommandSet() { Key = "Zoom", Text = "Zoom", ToolSide = EditorToolLocation.Top };
            tool.AddCommands(new EditorCommandKey(EditorCommandType.Zoom, EditorCommandZoomType.ZoomOut),
                             new EditorCommandKey(EditorCommandType.Zoom, EditorCommandZoomType.ZoomIn),
                             new EditorCommandKey(EditorCommandType.Zoom, EditorCommandZoomType.ZoomOriginal),
                             new EditorCommandKey(EditorCommandType.Zoom, EditorCommandZoomType.ZoomBestFitWidth));
            return tool;
        }
        /// <summary>
        /// Statický konstruktor pro toolbar: Format
        /// </summary>
        /// <returns></returns>
        internal static EditorCommandSet CreateFormat()
        {
            EditorCommandSet tool = new EditorCommandSet() { Key = "Format", Text = "Formátování", ToolSide = EditorToolLocation.Top };
            tool.AddCommands(new EditorCommandKey(EditorCommandType.ZOrder, EditorCommandZOrderType.ZOrderBottom),
                             new EditorCommandKey(EditorCommandType.ZOrder, EditorCommandZOrderType.ZOrderLower),
                             new EditorCommandKey(EditorCommandType.ZOrder, EditorCommandZOrderType.ZOrderHigher),
                             new EditorCommandKey(EditorCommandType.ZOrder, EditorCommandZOrderType.ZOrderTop),
                             EditorCommandKey.Separator,
                             new EditorCommandKey(EditorCommandType.Group, EditorCommandGroupType.ObjectGroup),
                             new EditorCommandKey(EditorCommandType.Group, EditorCommandGroupType.ObjectUnGroup),
                             EditorCommandKey.Separator,
                             new EditorCommandKey(EditorCommandType.Align, EditorCommandAlignType.AlignHLeft),
                             new EditorCommandKey(EditorCommandType.Align, EditorCommandAlignType.AlignHCenter),
                             new EditorCommandKey(EditorCommandType.Align, EditorCommandAlignType.AlignHRight),
                             new EditorCommandKey(EditorCommandType.Align, EditorCommandAlignType.AlignVTop),
                             new EditorCommandKey(EditorCommandType.Align, EditorCommandAlignType.AlignVMiddle),
                             new EditorCommandKey(EditorCommandType.Align, EditorCommandAlignType.AlignVBottom),
                             EditorCommandKey.Separator,
                             new EditorCommandKey(EditorCommandType.Equal, EditorCommandEqualType.EqualSizeWidth),
                             new EditorCommandKey(EditorCommandType.Equal, EditorCommandEqualType.EqualSizeHeight),
                             new EditorCommandKey(EditorCommandType.Equal, EditorCommandEqualType.EqualSpacingX),
                             new EditorCommandKey(EditorCommandType.Equal, EditorCommandEqualType.EqualSpacingY),
                             new EditorCommandKey(EditorCommandType.Equal, EditorCommandEqualType.EqualIntervalX),
                             new EditorCommandKey(EditorCommandType.Equal, EditorCommandEqualType.EqualIntervalY));
            return tool;
        }
        /// <summary>
        /// Statický konstruktor pro toolbar: Print
        /// </summary>
        /// <returns></returns>
        internal static EditorCommandSet CreateDocument()
        {
            EditorCommandSet tool = new EditorCommandSet() { Key = "Dokument", Text = "Uložení, tisk a náhled", ToolSide = EditorToolLocation.Top };
            tool.AddCommands(new EditorCommandKey(EditorCommandType.Document, EditorCommandDocumentType.DocumentNew),
                             new EditorCommandKey(EditorCommandType.Document, EditorCommandDocumentType.DocumentOpen),
                             new EditorCommandKey(EditorCommandType.Document, EditorCommandDocumentType.DocumentSave),
                             new EditorCommandKey(EditorCommandType.Document, EditorCommandDocumentType.DocumentSaveAs),
                             new EditorCommandKey(EditorCommandType.Document, EditorCommandDocumentType.DocumentPreview),
                             new EditorCommandKey(EditorCommandType.Document, EditorCommandDocumentType.DocumentPrint),
                             new EditorCommandKey(EditorCommandType.Document, EditorCommandDocumentType.DocumentEdit));
            return tool;
        }
        /// <summary>
        /// Statický konstruktor pro toolbar: AddObject
        /// </summary>
        /// <returns></returns>
        internal static EditorCommandSet CreateReportObject(IEnumerable<EditorCommand> commands)
        {
            EditorCommandSet tool = new EditorCommandSet() { Key = "ReportObject", Text = "Přidat objekt", ToolSide = EditorToolLocation.Left };
            tool.AddCommands(new EditorCommandKey(EditorCommandType.Object, EditorCommandObjectType.ObjectSelect),
                             new EditorCommandKey(EditorCommandType.Object, EditorCommandObjectType.ObjectAnchor),
                             new EditorCommandKey(EditorCommandType.Object, EditorCommandObjectType.ObjectLockInsert));

            // Další příkazy jsou uloženy v soupisu commands, vybereme pouze typ
            List<EditorCommand> reportCommands = commands.Where(cmd => cmd.CommandType == EditorCommandType.ObjectInsert && cmd.MenuInfo != null).ToList();
            reportCommands.Sort((a, b) => MenuItemInfo.CompareMenuInfo(a.MenuInfo, b.MenuInfo));

            string lastGroup = null;
            foreach (EditorCommand command in reportCommands)
            {
                MenuItemInfo menuInfo = command.MenuInfo;
                if (menuInfo == null) continue;
                string currGroup = (menuInfo.GroupName == null ? "" : menuInfo.GroupName);
                if (lastGroup == null || currGroup != lastGroup)
                {
                    tool.AddCommand(EditorCommandKey.Separator);
                    lastGroup = null;
                }
                tool.AddCommand(command.CommandKey);
                lastGroup = currGroup;
            }

            return tool;
        }
        
        #endregion
    }
    #endregion
    #region class EditorCommand : Jeden příkaz pro editor. Data, popisující účel a vzhled jednotlivého prvku (toolbuttonu, položky v menu) v UI rozhraní (toolbar, menu).
    /// <summary>
    /// EditorCommand : Příkaz pro editor, typicky pochází z UI a zpracovává jej editor.
    /// Instance třídy popisuje jeden příkaz, nenese ale další data.
    /// Specifikuje příkaz a jeho UI vzhled (ikona, text, tooltip).
    /// Statické metody mohou příkazy vytvářet a detekovat.
    /// </summary>
    public class EditorCommand
    {
        #region Konstrukce
        private EditorCommand()
        {
            CommandType = EditorCommandType.None;
            KeyModifiers = Keys.None;
            KeyCode = Keys.None;
        }
        #endregion
        #region Property
        /// <summary>
        /// Typ příkazu. Může existovat více různých příkazů, které mají shodný typ.
        /// Typ je například "Zoom", "Align", "Insert".
        /// Konkrétní akci určuje specifikátor uložený v CommandSpecification (pro Align je to druh Alignu, pro Insert je to typ objektu, atd).
        /// </summary>
        public EditorCommandType CommandType { get; private set; }
        /// <summary>
        /// Konkrétní akce. Rozšiřuje typ příkazu. Není povinný (například příkaz "Separator" nepotřebuje specifikaci), může být null.
        /// </summary>
        public object CommandSpecification { get; private set; }
        /// <summary>
        /// Klíč příkazu, obsahuje typ a specifikaci. Lze použít jako klíč v Dictionary.
        /// </summary>
        public EditorCommandKey CommandKey { get { return new EditorCommandKey(this.CommandType, this.CommandSpecification); } }
        /// <summary>
        /// Ikona do menu
        /// </summary>
        public Image MenuIcon { get; private set; }
        /// <summary>
        /// Ikona do toolbaru, menší (22 x 22 pixel)
        /// </summary>
        public Image ToolIconSmall { get; private set; }
        /// <summary>
        /// Ikona do toolbaru, větší (32 x 32 pixel)
        /// </summary>
        public Image ToolIconMedium { get; private set; }
        /// <summary>
        /// Text do položky menu
        /// </summary>
        public string MenuText { get; private set; }
        /// <summary>
        /// Text do toolbaru (pokud bude button zobrazen s textem)
        /// </summary>
        public string ToolText { get; private set; }
        /// <summary>
        /// Tooltip (do menu i do toolbaru)
        /// </summary>
        public string ToolTip { get; private set; }
        /// <summary>
        /// Přístupová klávesa, modifikátory (ctrl + alt + shift)
        /// </summary>
        public Keys KeyModifiers { get; private set; }
        /// <summary>
        /// Přístupová klávesa, kód bez modifikátorů
        /// </summary>
        public Keys KeyCode { get; private set; }
        /// <summary>
        /// Zdroj podkladů pro položku nabídky.
        /// private set způsobí, že se z setovaného objektu přenesou všechny informace do this (kromě klíče commandu).
        /// </summary>
        public MenuItemInfo MenuInfo
        {
            get { return this._MenuInfo; }
            private set
            {
                this._MenuInfo = value;
                if (value != null)
                {
                    this.ToolText = value.Name;
                    this.ToolTip = value.TooltipText;
                    this.ToolIconMedium = value.ImageMedium;
                    this.ToolIconSmall = value.ImageSmall;
                }
            }
        }
        private MenuItemInfo _MenuInfo;
        #endregion
        #region Public metody
        /// <summary>
        /// Zjistí, zda tento Command má být aktvován danou klávesou.
        /// Vrací true = ano.
        /// </summary>
        /// <param name="keyModifiers">Přístupová klávesa, modifikátory (ctrl + alt + shift)</param>
        /// <param name="keyCode">Přístupová klávesa, kód bez modifikátorů</param>
        /// <returns></returns>
        internal bool IsActiveForKey(Keys keyModifiers, Keys keyCode)
        {
            return (this.KeyCode != Keys.None && this.KeyModifiers == keyModifiers && this.KeyCode == keyCode);
        }
        #endregion
        #region Static tvorba seznamu příkazů
        /// <summary>
        /// Vytvoří a vrátí všechny Commandy.
        /// Každý command obsahuje ikonu, text, tooltip, přístupové klávesy.
        /// Vrácená sada obsahuje i separátor.
        /// </summary>
        /// <returns></returns>
        internal static IEnumerable<EditorCommand> CreateAll()
        {
            List<EditorCommand> list = new List<EditorCommand>();
            list.Add(new EditorCommand() { CommandType = EditorCommandType.Separator, CommandSpecification = null });
            
            list.Add(new EditorCommand() { CommandType = EditorCommandType.Document, CommandSpecification = EditorCommandDocumentType.DocumentNew, ToolText = "Open", ToolTip = "Ctrl+O:  Otevře existující sestavu", ToolIconSmall = IconLibrary22.DocumentNew_FromFile, KeyModifiers = Keys.Control, KeyCode = Keys.N });
            list.Add(new EditorCommand() { CommandType = EditorCommandType.Document, CommandSpecification = EditorCommandDocumentType.DocumentOpen, ToolText = "Open", ToolTip = "Ctrl+O:  Otevře existující sestavu", ToolIconSmall = IconLibrary22.DocumentOpen_FromFile, KeyModifiers = Keys.Control, KeyCode = Keys.O });
            list.Add(new EditorCommand() { CommandType = EditorCommandType.Document, CommandSpecification = EditorCommandDocumentType.DocumentSave, ToolText = "Save", ToolTip = "Ctrl+S:  Uloží aktuální stav", ToolIconSmall = IconLibrary22.DocumentSaveB_FromFile, KeyModifiers = Keys.Control, KeyCode = Keys.S });
            list.Add(new EditorCommand() { CommandType = EditorCommandType.Document, CommandSpecification = EditorCommandDocumentType.DocumentSaveAs, ToolText = "SaveAs", ToolTip = "Uloží aktuální stav do zvoleného souboru", ToolIconSmall = IconLibrary22.DocumentSaveAs_FromFile });
            list.Add(new EditorCommand() { CommandType = EditorCommandType.Document, CommandSpecification = EditorCommandDocumentType.DocumentRevert, ToolText = "Revert", ToolTip = "Obnoví stav dokumentu na posledně uložený stav", ToolIconSmall = IconLibrary22.DocumentRevert_FromFile });
            list.Add(new EditorCommand() { CommandType = EditorCommandType.Document, CommandSpecification = EditorCommandDocumentType.DocumentPreview, ToolText = "Preview", ToolTip = "Zobrazí náhled sestavy", ToolIconSmall = IconLibrary22.DocumentPreview_FromFile});
            list.Add(new EditorCommand() { CommandType = EditorCommandType.Document, CommandSpecification = EditorCommandDocumentType.DocumentPrint, ToolText = "Print", ToolTip = "Umožní vytisknout sestavu", ToolIconSmall = IconLibrary22.DocumentPrint_FromFile, KeyModifiers = Keys.Control, KeyCode = Keys.P });
            list.Add(new EditorCommand() { CommandType = EditorCommandType.Document, CommandSpecification = EditorCommandDocumentType.DocumentEdit, ToolText = "Editor", ToolTip = "Konec náhledu, návrat do editoru", ToolIconSmall = IconLibrary22.DocumentEdit_FromFile, KeyModifiers = Keys.None, KeyCode = Keys.Escape });
            list.Add(new EditorCommand() { CommandType = EditorCommandType.Edit, CommandSpecification = EditorCommandEditType.EditCut, ToolText = "Cut", ToolTip = "Ctrl+X:  Vybrané prvky odebere a umístí do schránky. Pak je lze vložit i do jiné sestavy", ToolIconSmall = IconLibrary22.EditCut_FromFile, KeyModifiers = Keys.Control, KeyCode = Keys.X });
            list.Add(new EditorCommand() { CommandType = EditorCommandType.Edit, CommandSpecification = EditorCommandEditType.EditCopy, ToolText = "Copy", ToolTip = "Ctrl+C:  Vybrané prvky zkopíruje do schránky. Pak je lze vložit i do jiné sestavy", ToolIconSmall = IconLibrary22.EditCopy_FromFile, KeyModifiers = Keys.Control, KeyCode = Keys.C });
            list.Add(new EditorCommand() { CommandType = EditorCommandType.Edit, CommandSpecification = EditorCommandEditType.EditPaste, ToolText = "Paste", ToolTip = "Ctrl+V:  Ze schránky vloží prvky, které do ní byly vloženy.", ToolIconSmall = IconLibrary22.EditPaste_FromFile, KeyModifiers = Keys.Control, KeyCode = Keys.V });
            list.Add(new EditorCommand() { CommandType = EditorCommandType.Edit, CommandSpecification = EditorCommandEditType.EditDelete, ToolText = "Delete", ToolTip = "Del: Smaže vybrané prvky.", ToolIconSmall = IconLibrary22.EditDelete_FromFile, KeyModifiers = Keys.None, KeyCode = Keys.Delete });
            list.Add(new EditorCommand() { CommandType = EditorCommandType.Edit, CommandSpecification = EditorCommandEditType.EditUndo, ToolText = "Undo", ToolTip = "O krok zpět v editaci (odvolá poslední změnu v editaci)", ToolIconSmall = IconLibrary22.EditUndo_FromFile, KeyModifiers = Keys.Control, KeyCode = Keys.Z });
            list.Add(new EditorCommand() { CommandType = EditorCommandType.Edit, CommandSpecification = EditorCommandEditType.EditRedo, ToolText = "Redo", ToolTip = "O krok vpřed (znovu provede změnu, která byla posledně odvolaná)", ToolIconSmall = IconLibrary22.EditRedo_FromFile, KeyModifiers = Keys.Control, KeyCode = Keys.Y });
            list.Add(new EditorCommand() { CommandType = EditorCommandType.Edit, CommandSpecification = EditorCommandZOrderType.ZOrderBottom, ToolText = "Dozadu", ToolTip = "Přemístí objekt(y) dozadu pod ostatní objekty", ToolIconSmall = IconLibrary22.LayerBottom_FromFile, KeyModifiers = Keys.Control, KeyCode = Keys.End });
            list.Add(new EditorCommand() { CommandType = EditorCommandType.Edit, CommandSpecification = EditorCommandZOrderType.ZOrderLower, ToolText = "Níž", ToolTip = "Přemístí objekt(y) o 1 níže", ToolIconSmall = IconLibrary22.LayerBackward_FromFile, KeyModifiers = Keys.Control, KeyCode = Keys.PageDown });
            list.Add(new EditorCommand() { CommandType = EditorCommandType.Edit, CommandSpecification = EditorCommandZOrderType.ZOrderHigher, ToolText = "Výš", ToolTip = "Přemístí objekt(y) o 1 výše", ToolIconSmall = IconLibrary22.LayerForward_FromFile, KeyModifiers = Keys.Control, KeyCode = Keys.PageUp });
            list.Add(new EditorCommand() { CommandType = EditorCommandType.Edit, CommandSpecification = EditorCommandZOrderType.ZOrderTop, ToolText = "Nahoru", ToolTip = "Přemístí objekt(y) dopředu nad ostatní objekty", ToolIconSmall = IconLibrary22.LayerTop_FromFile, KeyModifiers = Keys.Control, KeyCode = Keys.Home });
            list.Add(new EditorCommand() { CommandType = EditorCommandType.Align, CommandSpecification = EditorCommandAlignType.AlignHLeft, ToolText = "Vlevo", ToolTip = "Zarovná všechny vybrané objekty na levou stranu", ToolIconSmall = IconLibrary22.AlignHorizontalLeft_FromFile, KeyModifiers = Keys.None, KeyCode = Keys.L });
            list.Add(new EditorCommand() { CommandType = EditorCommandType.Align, CommandSpecification = EditorCommandAlignType.AlignHCenter, ToolText = "Centrovat", ToolTip = "Zarovná všechny vybrané objekty na svislou osu", ToolIconSmall = IconLibrary22.AlignHorizontalCenter_FromFile, KeyModifiers = Keys.None, KeyCode = Keys.E });
            list.Add(new EditorCommand() { CommandType = EditorCommandType.Align, CommandSpecification = EditorCommandAlignType.AlignHRight, ToolText = "Vpravo", ToolTip = "Zarovná všechny vybrané objekty na pravou stranu", ToolIconSmall = IconLibrary22.AlignHorizontalRight_FromFile, KeyModifiers = Keys.None, KeyCode = Keys.R });
            list.Add(new EditorCommand() { CommandType = EditorCommandType.Align, CommandSpecification = EditorCommandAlignType.AlignVTop, ToolText = "Nahoru", ToolTip = "Zarovná všechny vybrané objekty nahoru", ToolIconSmall = IconLibrary22.AlignVerticalTop_FromFile, KeyModifiers = Keys.None, KeyCode = Keys.T });
            list.Add(new EditorCommand() { CommandType = EditorCommandType.Align, CommandSpecification = EditorCommandAlignType.AlignVMiddle, ToolText = "Na střed", ToolTip = "Zarovná všechny vybrané objekty na vodorovnou osu", ToolIconSmall = IconLibrary22.AlignVerticalCenter_FromFile, KeyModifiers = Keys.None, KeyCode = Keys.M });
            list.Add(new EditorCommand() { CommandType = EditorCommandType.Align, CommandSpecification = EditorCommandAlignType.AlignVBottom, ToolText = "Dolů", ToolTip = "Zarovná všechny vybrané objekty dolů", ToolIconSmall = IconLibrary22.AlignVerticalBottom_FromFile, KeyModifiers = Keys.None, KeyCode = Keys.B });
            list.Add(new EditorCommand() { CommandType = EditorCommandType.Equal, CommandSpecification = EditorCommandEqualType.EqualSizeWidth, ToolText = "Šířka", ToolTip = "Nastaví všechny vybrané objekty stejně široké", ToolIconSmall = null });
            list.Add(new EditorCommand() { CommandType = EditorCommandType.Equal, CommandSpecification = EditorCommandEqualType.EqualSizeHeight, ToolText = "Výška", ToolTip = "Nastaví všechny vybrané objekty stejně vysoké", ToolIconSmall = null });
            list.Add(new EditorCommand() { CommandType = EditorCommandType.Equal, CommandSpecification = EditorCommandEqualType.EqualSpacingX, ToolText = "Mezery X", ToolTip = "Nastaví mezi všechny vybrané objekty vodorovně stejně široké mezery", ToolIconSmall = IconLibrary22.DistributeHorizontalEqual_FromFile });
            list.Add(new EditorCommand() { CommandType = EditorCommandType.Equal, CommandSpecification = EditorCommandEqualType.EqualSpacingY, ToolText = "Mezery Y", ToolTip = "Nastaví mezi všechny vybrané objekty svisle stejně vysoké mezery", ToolIconSmall = IconLibrary22.DistributeVerticalEqual_FromFile });
            list.Add(new EditorCommand() { CommandType = EditorCommandType.Equal, CommandSpecification = EditorCommandEqualType.EqualIntervalX, ToolText = "Pravidelně X", ToolTip = "Rozmístí vodorovně všechny vybrané objekty na shodné vzdálenosti", ToolIconSmall = IconLibrary22.DistributeHorizontalLeft_FromFile });
            list.Add(new EditorCommand() { CommandType = EditorCommandType.Equal, CommandSpecification = EditorCommandEqualType.EqualIntervalY, ToolText = "Pravidelně Y", ToolTip = "Rozmístí svisle všechny vybrané objekty na shodné vzdálenosti", ToolIconSmall = IconLibrary22.DistributeVerticalBottom_FromFile });
            list.Add(new EditorCommand() { CommandType = EditorCommandType.ZOrder, CommandSpecification = EditorCommandZOrderType.ZOrderBottom, ToolText = "Dozadu", ToolTip = "Přemístí objekt(y) dozadu pod ostatní objekty", ToolIconSmall = IconLibrary22.LayerBottom_FromFile, KeyModifiers = Keys.Control, KeyCode = Keys.End });
            list.Add(new EditorCommand() { CommandType = EditorCommandType.ZOrder, CommandSpecification = EditorCommandZOrderType.ZOrderLower, ToolText = "Níž", ToolTip = "Přemístí objekt(y) o 1 níže", ToolIconSmall = IconLibrary22.LayerBackward_FromFile, KeyModifiers = Keys.Control, KeyCode = Keys.PageDown });
            list.Add(new EditorCommand() { CommandType = EditorCommandType.ZOrder, CommandSpecification = EditorCommandZOrderType.ZOrderHigher, ToolText = "Výš", ToolTip = "Přemístí objekt(y) o 1 výše", ToolIconSmall = IconLibrary22.LayerForward_FromFile, KeyModifiers = Keys.Control, KeyCode = Keys.PageUp });
            list.Add(new EditorCommand() { CommandType = EditorCommandType.ZOrder, CommandSpecification = EditorCommandZOrderType.ZOrderTop, ToolText = "Nahoru", ToolTip = "Přemístí objekt(y) dopředu nad ostatní objekty", ToolIconSmall = IconLibrary22.LayerTop_FromFile, KeyModifiers = Keys.Control, KeyCode = Keys.Home });
            list.Add(new EditorCommand() { CommandType = EditorCommandType.Object, CommandSpecification = EditorCommandObjectType.ObjectSelect, ToolText = "Select", ToolTip = "Výběr objektu (objektů) pro další práci", ToolIconSmall = IconLibrary22.Select_FromFile });
            list.Add(new EditorCommand() { CommandType = EditorCommandType.Object, CommandSpecification = EditorCommandObjectType.ObjectAnchor, ToolText = "Anchors", ToolTip = "Umožní zobrazit a měnit ukotvení objektů v rámci jejich svazku", ToolIconSmall = IconLibrary22.ViewFullscreen_FromFile });
            list.Add(new EditorCommand() { CommandType = EditorCommandType.Object, CommandSpecification = EditorCommandObjectType.ObjectLockInsert, ToolText = "Insert lock", ToolTip = "Umožní přidávat nové objekty bez nutnosti jejich opakovaného výběruv nabídce", ToolIconSmall = IconLibrary22.LockEdit_FromFile });
            list.Add(new EditorCommand() { CommandType = EditorCommandType.Group, CommandSpecification = EditorCommandGroupType.ObjectGroup, ToolText = "Group", ToolTip = "Seskupí vybrané objekty do jedné skupiny", ToolIconSmall = IconLibrary22.ObjectGroup_FromFile, KeyModifiers = Keys.Control, KeyCode = Keys.G });
            list.Add(new EditorCommand() { CommandType = EditorCommandType.Group, CommandSpecification = EditorCommandGroupType.ObjectUnGroup, ToolText = "Ungroup", ToolTip = "Rozdělí vybrané skupiny objektů na jednotlivé objekty", ToolIconSmall = IconLibrary22.ObjectUngroup_FromFile, KeyModifiers = Keys.Control, KeyCode = Keys.U });
            list.Add(new EditorCommand() { CommandType = EditorCommandType.Zoom, CommandSpecification = EditorCommandZoomType.ZoomOriginal, ToolText = "1:1", ToolTip = "Nastaví měřítko 1:1 (zobrazení na monitoru odpovídá reálným rozměrům sestavy)", ToolIconSmall = IconLibrary22.ZoomOriginal_FromFile });
            list.Add(new EditorCommand() { CommandType = EditorCommandType.Zoom, CommandSpecification = EditorCommandZoomType.ZoomIn, ToolText = "Zoom In", ToolTip = "Zvětší měřítko - zobrazí méně prvků, větších", ToolIconSmall = IconLibrary22.ZoomIn_FromFile });
            list.Add(new EditorCommand() { CommandType = EditorCommandType.Zoom, CommandSpecification = EditorCommandZoomType.ZoomOut, ToolText = "Zoom Out", ToolTip = "Zmenší měřítko - zobrazí více prvků, menších", ToolIconSmall = IconLibrary22.ZoomOut_FromFile });
            list.Add(new EditorCommand() { CommandType = EditorCommandType.Zoom, CommandSpecification = EditorCommandZoomType.ZoomBestFitWidth, ToolText = "Zoom Fit", ToolTip = "Upraví měřítko tak, aby byla zobrazena celá stránka", ToolIconSmall = IconLibrary22.ZoomFitBest_FromFile });

            List<EditorCommand> reportObjectCommands = GetReportObjectCommands();
            list.AddRange(reportObjectCommands);

            return list;
        }
        /// <summary>
        /// Vytvoří a vrátí seznam příkazů editoru (UI) vytvořený ze soupisu aktuálně dostupných tříd implementujících IReportObject.
        /// Příkazy mají jako CommandType uveden typ EditorCommandType.ObjectInsert, a v CommandSpecification mají Type objektu.
        /// Jde tedy o commandy UI, které umožní uživateli vkládat nové objekty do reportu.
        /// </summary>
        /// <returns></returns>
        private static List<EditorCommand> GetReportObjectCommands()
        {
            List<EditorCommand> result = new List<EditorCommand>();

            IEnumerable<IReportObject> reportObjects = ReportObject.ReportObjects;
            if (reportObjects != null)
            {
                foreach (IReportObject reportObject in reportObjects)
                {
                    EditorCommand command = new EditorCommand() { MenuInfo = reportObject.MenuInfo, CommandType = EditorCommandType.ObjectInsert, CommandSpecification = reportObject.GetType() };
                    result.Add(command);
                }
            }
            return result;
        }
        #endregion
    }
    #endregion
    #region class EditorCommandKey : Klíč příkazu pro editor. Obsahuje CommandType a CommandSpecification.
    /// <summary>
    /// EditorCommandKey : klíč příkazu pro editor. Obsahuje CommandType a CommandSpecification.
    /// Použitelný do Hashtable (Dictionary). Implementuje IEquatable a == a =!
    /// </summary>
    public class EditorCommandKey : IEquatable<EditorCommandKey>
    {
        /// <summary>
        /// Konstruktor
        /// </summary>
        /// <param name="commandType"></param>
        /// <param name="commandSpecification"></param>
        public EditorCommandKey(EditorCommandType commandType, object commandSpecification)
        {
            this.CommandType = commandType;
            this.CommandSpecification = commandSpecification;
        }
        /// <summary>
        /// Typ příkazu. Může existovat více různých příkazů, které mají shodný typ.
        /// Typ je například "Zoom", "Align", "Insert".
        /// Konkrétní akci určuje specifikátor uložený v CommandSpecification (pro Align je to druh Alignu, pro Insert je to typ objektu, atd).
        /// </summary>
        public EditorCommandType CommandType { get; private set; }
        /// <summary>
        /// Konkrétní akce. Rozšiřuje typ příkazu. Není povinný (například příkaz "Separator" nepotřebuje specifikaci).
        /// </summary>
        public object CommandSpecification { get; private set; }
        /// <summary>
        /// Vizualizace
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return this.CommandType.ToString() +
                (this.CommandSpecification == null ? "" : ": " + this.CommandSpecification.ToString());
        }
        /// <summary>
        /// Vrací klíč pro command Separátor
        /// </summary>
        public static EditorCommandKey Separator { get { return new EditorCommandKey(EditorCommandType.Separator, null); } }
        #region Hascode a Equals, IEquatable<EditorCommandKey> Members, ==, !=
        /// <summary>
        /// Vrací hashcode
        /// </summary>
        /// <returns></returns>
        public override int GetHashCode()
        {
            return this.CommandType.GetHashCode() ^ (this.CommandSpecification == null ? 0 : this.CommandSpecification.GetHashCode());
        }
        /// <summary>
        /// Určí shodu objektu
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public override bool Equals(object obj)
        {
            EditorCommandKey other = obj as EditorCommandKey;
            if (other == null) return false;
            return _EqualsTo(this, other);
        }
        /// <summary>
        /// Určí shodu objektu
        /// </summary>
        /// <param name="other"></param>
        /// <returns></returns>
        bool IEquatable<EditorCommandKey>.Equals(EditorCommandKey other)
        {
            return _EqualsTo(this, other);
        }
        private static bool _EqualsTo(EditorCommandKey a, EditorCommandKey b)
        {
            bool aNull = Object.Equals(a, null);
            bool bNull = Object.Equals(b, null);
            if (aNull && bNull) return true;
            if (aNull || bNull) return false;
            if (a.CommandType != b.CommandType) return false;
            if (a.CommandSpecification == null && b.CommandSpecification == null) return true;    // Obě specifikace jsou null => shoda
            if (a.CommandSpecification == null) return false;
            if (b.CommandSpecification == null) return false;
            return (a.CommandSpecification.Equals(b.CommandSpecification));                       // Využívám Equals
        }
        /// <summary>
        /// Operátor porovnání
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static bool operator ==(EditorCommandKey a, EditorCommandKey b)
        {
            return _EqualsTo(a, b);
        }
        /// <summary>
        /// Operátor nerovnosti
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static bool operator !=(EditorCommandKey a, EditorCommandKey b)
        {
            return !_EqualsTo(a, b);
        }
        #endregion
        #region TryGetSpecification()
        /// <summary>
        /// Získá specifikaci příkazu přetypovanou na požadovaný typ, vrátí true = úspěch
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="result"></param>
        /// <returns></returns>
        public bool TryGetSpecification<T>(out T result)
        {
            if (this.CommandSpecification is T)
            {
                result = (T)this.CommandSpecification;
                return true;
            }
            result = default(T);
            return false;
        }
        #endregion
    }
    #endregion
    #region enum EditorCommandType : Základní příkazy editoru, enumy EditorCommand***Type : Konkrétní typy akcí
    /// <summary>
    /// EditorCommandType : Příkazy editoru
    /// </summary>
    public enum EditorCommandType
    {
        /// <summary>Žádná akce</summary>
        None = 0,
        /// <summary>Oddělovač nabídek, žádná funkce</summary>
        Separator,
        /// <summary>Dokument (Nový, Otevřít, Uložit, Print, Preview)</summary>
        Document,
        /// <summary>Editace (Clipboard, Delete, Undo/Redo)</summary>
        Edit,
        /// <summary>ZOrder: pozice na ose Z</summary>
        ZOrder,
        /// <summary>Align objektů</summary>
        Align,
        /// <summary>Shodné rozměry/vzdálenosti objektů</summary>
        Equal,
        /// <summary>Grupování objektů</summary>
        Group,
        /// <summary>Změna měřítka</summary>
        Zoom,
        /// <summary>Práce s objekty mimo Insert</summary>
        Object,
        /// <summary>Editor: vložení objektu (ve specifikaci commandu je typ objektu)</summary>
        ObjectInsert
    }
    /// <summary>
    /// Specifikace příkazu typu Dokument
    /// </summary>
    public enum EditorCommandDocumentType
    {
        /// <summary>Nový dokument</summary>
        DocumentNew,
        /// <summary>Otevřít existující dokument</summary>
        DocumentOpen,
        /// <summary>Uložit dokument</summary>
        DocumentSave,
        /// <summary>Uložit dokument jinam</summary>
        DocumentSaveAs,
        /// <summary>Vrátit se k posledně uloženému stavu</summary>
        DocumentRevert,
        /// <summary>Zavřít</summary>
        DocumentClose,
        /// <summary>Preview document</summary>
        DocumentPreview,
        /// <summary>Print document with dialog</summary>
        DocumentPrint,
        /// <summary>Konec Preview documentu, návrat do editoru</summary>
        DocumentEdit,
        /// <summary>Editovat ReportData pro RootBand</summary>
        DocumentEditRootData
    }
    /// <summary>
    /// Specifikace příkazu typu Edit
    /// </summary>
    public enum EditorCommandEditType
    {
        /// <summary>Cut to clipboard</summary>
        EditCut,
        /// <summary>Copy to clipboard</summary>
        EditCopy,
        /// <summary>Paste from clipboard</summary>
        EditPaste,
        /// <summary>Delete selected</summary>
        EditDelete,
        /// <summary>Undo last change</summary>
        EditUndo,
        /// <summary>Redo last change</summary>
        EditRedo
    }
    /// <summary>
    /// Specifikace příkazu typu ZOrder
    /// </summary>
    public enum EditorCommandZOrderType
    {
        /// <summary>ZOrder: To Bottom</summary>
        ZOrderBottom,
        /// <summary>ZOrder: One level lower</summary>
        ZOrderLower,
        /// <summary>ZOrder: One level higher</summary>
        ZOrderHigher,
        /// <summary>ZOrder: To Top</summary>
        ZOrderTop
    }
    /// <summary>
    /// Specifikace příkazu typu Align
    /// </summary>
    public enum EditorCommandAlignType
    {   
        /// <summary>Align: horizontal - left</summary>
        AlignHLeft,
        /// <summary>Align: horizontal - center</summary>
        AlignHCenter,
        /// <summary>Align: horizontal - right</summary>
        AlignHRight,
        /// <summary>Align: vertical - top</summary>
        AlignVTop,
        /// <summary>Align: vertical - middle</summary>
        AlignVMiddle,
        /// <summary>Align: vertical - bottom</summary>
        AlignVBottom
    }
    /// <summary>
    /// Specifikace příkazu typu Equal (size, space, distance)
    /// </summary>
    public enum EditorCommandEqualType
    {
        /// <summary>Equal size: Width</summary>
        EqualSizeWidth,
        /// <summary>Equal size: Height</summary>
        EqualSizeHeight,
        /// <summary>Equal spacing: on X axis (spacing is distance between Object1.End and Object2.Begin)</summary>
        EqualSpacingX,
        /// <summary>Equal spacing: on Y axis (spacing is distance between Object1.End and Object2.Begin)</summary>
        EqualSpacingY,
        /// <summary>Equal interval: on X axis (interval is distance between Object1.Begin and Object2.Begin)</summary>
        EqualIntervalX,
        /// <summary>Equal interval: on Y axis (interval is distance between Object1.Begin and Object2.Begin)</summary>
        EqualIntervalY
    }
    /// <summary>
    /// Specifikace příkazu typu Group
    /// </summary>
    public enum EditorCommandGroupType
    {
        /// <summary>Group selected objects</summary>
        ObjectGroup,
        /// <summary>UnGroup objects in selected groups</summary>
        ObjectUnGroup
    }
    /// <summary>
    /// Specifikace příkazu typu Zoom
    /// </summary>
    public enum EditorCommandZoomType
    {
        /// <summary>Zoom: original size (1mm = 1mm)</summary>
        ZoomOriginal,
        /// <summary>Zoom: in (large detail)</summary>
        ZoomIn,
        /// <summary>Zoom: out (small items)</summary>
        ZoomOut,
        /// <summary>Zoom: show whole width</summary>
        ZoomBestFitWidth,
        /// <summary>Zoom: show whole page</summary>
        ZoomWholePage
    }
    /// <summary>
    /// Specifikace příkazu typu Object
    /// </summary>
    public enum EditorCommandObjectType
    {
        /// <summary>Object: select object (for move, propertychange, etc)</summary>
        ObjectSelect,
        /// <summary>Object: show anchors of object and edit anchors</summary>
        ObjectAnchor,
        /// <summary>Object: lock insert mode (after insert new object stay in insert mode)</summary>
        ObjectLockInsert
    }
    #endregion
}
